"""
文件扫描器模块
用于扫描文件夹中的视频文件并提取基本信息
"""

import os
import logging
from typing import List, Dict, Tuple, Optional
from pathlib import Path
import mimetypes
from dataclasses import dataclass
from datetime import datetime

try:
    import moviepy.editor as mp
    MOVIEPY_AVAILABLE = True
except ImportError:
    MOVIEPY_AVAILABLE = False
    logging.warning("MoviePy未安装，部分视频信息获取功能不可用")


@dataclass
class VideoFileInfo:
    """视频文件信息"""
    path: str
    filename: str
    size: int  # 文件大小（字节）
    duration: float  # 时长（秒）
    resolution: Tuple[int, int]  # 分辨率 (width, height)
    fps: float  # 帧率
    format: str  # 文件格式
    created_time: datetime  # 创建时间
    modified_time: datetime  # 修改时间
    is_valid: bool  # 是否为有效视频文件
    speed: float = 1.0  # 播放速率，默认1.0（正常速度）
    error_message: Optional[str] = None  # 错误信息


class VideoFileScanner:
    """视频文件扫描器"""
    
    # 支持的视频格式
    SUPPORTED_VIDEO_EXTENSIONS = {
        '.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm',
        '.m4v', '.3gp', '.ogv', '.ts', '.mts', '.m2ts', '.vob'
    }
    
    # 支持的视频MIME类型
    SUPPORTED_VIDEO_MIMETYPES = {
        'video/mp4', 'video/avi', 'video/quicktime', 'video/x-msvideo',
        'video/x-matroska', 'video/webm', 'video/x-flv'
    }
    
    def __init__(self, max_file_size: int = 5 * 1024 * 1024 * 1024):  # 5GB默认上限
        """
        初始化扫描器
        
        Args:
            max_file_size: 单个文件大小上限（字节）
        """
        self.max_file_size = max_file_size
        self.logger = logging.getLogger(__name__)
    
    def scan_folder(self, folder_path: str, recursive: bool = False) -> List[VideoFileInfo]:
        """
        扫描文件夹中的视频文件
        
        Args:
            folder_path: 文件夹路径
            recursive: 是否递归扫描子文件夹
            
        Returns:
            视频文件信息列表
        """
        if not os.path.exists(folder_path):
            self.logger.error(f"文件夹不存在: {folder_path}")
            return []
        
        if not os.path.isdir(folder_path):
            self.logger.error(f"路径不是文件夹: {folder_path}")
            return []
        
        video_files = []
        folder_path = Path(folder_path)
        
        self.logger.info(f"开始扫描文件夹: {folder_path}")
        
        try:
            # 获取文件列表
            if recursive:
                file_pattern = "**/*"
                files = folder_path.glob(file_pattern)
            else:
                files = folder_path.iterdir()
            
            for file_path in files:
                if file_path.is_file():
                    # 检查是否为视频文件
                    if self._is_video_file(file_path):
                        video_info = self._get_video_info(file_path)
                        if video_info:
                            video_files.append(video_info)
                            self.logger.debug(f"发现视频文件: {file_path.name}")
        
        except Exception as e:
            self.logger.error(f"扫描文件夹时出错: {e}")
        
        self.logger.info(f"扫描完成，找到 {len(video_files)} 个视频文件")
        return video_files
    
    def scan_files(self, file_paths: List[str]) -> List[VideoFileInfo]:
        """
        扫描指定的文件列表
        
        Args:
            file_paths: 文件路径列表
            
        Returns:
            视频文件信息列表
        """
        video_files = []
        
        for file_path in file_paths:
            file_path = Path(file_path)
            
            if not file_path.exists():
                self.logger.warning(f"文件不存在: {file_path}")
                continue
            
            if not file_path.is_file():
                self.logger.warning(f"路径不是文件: {file_path}")
                continue
            
            if self._is_video_file(file_path):
                video_info = self._get_video_info(file_path)
                if video_info:
                    video_files.append(video_info)
        
        return video_files
    
    def _is_video_file(self, file_path: Path) -> bool:
        """
        检查文件是否为视频文件
        
        Args:
            file_path: 文件路径
            
        Returns:
            是否为视频文件
        """
        # 检查文件扩展名
        ext = file_path.suffix.lower()
        if ext in self.SUPPORTED_VIDEO_EXTENSIONS:
            return True
        
        # 检查MIME类型
        mime_type, _ = mimetypes.guess_type(str(file_path))
        if mime_type and mime_type in self.SUPPORTED_VIDEO_MIMETYPES:
            return True
        
        return False
    
    def _get_video_info(self, file_path: Path) -> Optional[VideoFileInfo]:
        """
        获取视频文件信息
        
        Args:
            file_path: 视频文件路径
            
        Returns:
            视频文件信息，失败返回None
        """
        try:
            # 获取文件基本信息
            stat = file_path.stat()
            file_size = stat.st_size
            created_time = datetime.fromtimestamp(stat.st_ctime)
            modified_time = datetime.fromtimestamp(stat.st_mtime)
            
            # 检查文件大小
            if file_size > self.max_file_size:
                self.logger.warning(f"文件过大，跳过: {file_path.name} ({file_size / 1024 / 1024:.1f}MB)")
                return VideoFileInfo(
                    path=str(file_path),
                    filename=file_path.name,
                    size=file_size,
                    duration=0,
                    resolution=(0, 0),
                    fps=0,
                    format=file_path.suffix.lower()[1:],
                    created_time=created_time,
                    modified_time=modified_time,
                    is_valid=False,
                    error_message=f"文件过大 ({file_size / 1024 / 1024:.1f}MB > {self.max_file_size / 1024 / 1024:.1f}MB)"
                )
            
            # 获取视频详细信息
            duration = 0
            resolution = (0, 0)
            fps = 0
            is_valid = True
            error_message = None
            
            if MOVIEPY_AVAILABLE:
                try:
                    with mp.VideoFileClip(str(file_path)) as clip:
                        duration = clip.duration or 0
                        if hasattr(clip, 'size') and clip.size:
                            resolution = clip.size
                        fps = clip.fps or 0
                except Exception as e:
                    self.logger.warning(f"无法获取视频信息: {file_path.name} - {e}")
                    is_valid = False
                    error_message = str(e)
            else:
                # 如果MoviePy不可用，创建基本信息
                self.logger.warning(f"MoviePy不可用，无法获取详细视频信息: {file_path.name}")
                is_valid = True  # 假设文件有效
            
            return VideoFileInfo(
                path=str(file_path),
                filename=file_path.name,
                size=file_size,
                duration=duration,
                resolution=resolution,
                fps=fps,
                format=file_path.suffix.lower()[1:],
                created_time=created_time,
                modified_time=modified_time,
                is_valid=is_valid,
                error_message=error_message
            )
        
        except Exception as e:
            self.logger.error(f"获取视频文件信息失败: {file_path} - {e}")
            return None
    
    def get_summary(self, video_files: List[VideoFileInfo]) -> Dict:
        """
        获取扫描结果摘要
        
        Args:
            video_files: 视频文件列表
            
        Returns:
            摘要信息
        """
        valid_files = [f for f in video_files if f.is_valid]
        invalid_files = [f for f in video_files if not f.is_valid]
        
        total_duration = sum(f.duration for f in valid_files)
        total_size = sum(f.size for f in valid_files)
        
        # 统计格式分布
        format_count = {}
        for f in valid_files:
            fmt = f.format
            format_count[fmt] = format_count.get(fmt, 0) + 1
        
        # 统计分辨率分布
        resolution_count = {}
        for f in valid_files:
            if f.resolution[0] > 0 and f.resolution[1] > 0:
                res_str = f"{f.resolution[0]}x{f.resolution[1]}"
                resolution_count[res_str] = resolution_count.get(res_str, 0) + 1
        
        return {
            "total_files": len(video_files),
            "valid_files": len(valid_files),
            "invalid_files": len(invalid_files),
            "total_duration": total_duration,
            "total_duration_formatted": self._format_duration(total_duration),
            "total_size": total_size,
            "total_size_formatted": self._format_size(total_size),
            "format_distribution": format_count,
            "resolution_distribution": resolution_count,
            "invalid_file_errors": [
                {"filename": f.filename, "error": f.error_message}
                for f in invalid_files if f.error_message
            ]
        }
    
    def _format_duration(self, seconds: float) -> str:
        """格式化时长"""
        if seconds <= 0:
            return "0:00"
        
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        secs = int(seconds % 60)
        
        if hours > 0:
            return f"{hours}:{minutes:02d}:{secs:02d}"
        else:
            return f"{minutes}:{secs:02d}"
    
    def _format_size(self, bytes_size: int) -> str:
        """格式化文件大小"""
        if bytes_size < 1024:
            return f"{bytes_size} B"
        elif bytes_size < 1024 * 1024:
            return f"{bytes_size / 1024:.1f} KB"
        elif bytes_size < 1024 * 1024 * 1024:
            return f"{bytes_size / 1024 / 1024:.1f} MB"
        else:
            return f"{bytes_size / 1024 / 1024 / 1024:.1f} GB"


# 便捷函数
def scan_video_folder(folder_path: str, recursive: bool = False) -> Tuple[List[VideoFileInfo], Dict]:
    """
    便捷函数：扫描文件夹中的视频文件
    
    Args:
        folder_path: 文件夹路径
        recursive: 是否递归扫描
        
    Returns:
        (视频文件列表, 摘要信息)
    """
    scanner = VideoFileScanner()
    video_files = scanner.scan_folder(folder_path, recursive)
    summary = scanner.get_summary(video_files)
    return video_files, summary


def scan_video_files(file_paths: List[str]) -> Tuple[List[VideoFileInfo], Dict]:
    """
    便捷函数：扫描指定的视频文件
    
    Args:
        file_paths: 文件路径列表
        
    Returns:
        (视频文件列表, 摘要信息)
    """
    scanner = VideoFileScanner()
    video_files = scanner.scan_files(file_paths)
    summary = scanner.get_summary(video_files)
    return video_files, summary